import { Dep } from './Dep.js';

/**
 * 附加到每个被观察对象的观察者类。
 *附加后，观察者将目标对象的属性键转换为getter/setter，
 *收集依赖项并发送更新。
 **/

// 根据对象类型决定如何做响应化
export class Observer {
  constructor(targetObject) {
    // this.targetObject = targetObject;
    // 创建一个Dep和当前key一一对应
    //this.dep = new Dep();

    //在 targetObject 上 添加  Observer 实例, setter时 通知该实例
    // def(targetObject, '__ob__', this);

    // 判断其类型,数组另作处理(todo)
    if (typeof targetObject === 'object') {
      this.walk(targetObject);
    }
  }

  /**
   *遍历所有属性并将它们转换为getter/setter。
   *当值类型为Object时才应调用此方法。
   */
  walk(obj) {
    console.log('walk start>>>>>>');
    Object.keys(obj).forEach(key => {
      console.log('walk>>' + key + '==' + obj[key]);
      defineReactive(obj, key, obj[key]);
    });
    console.log('<<<<<<<<<<<<<<<<walk end');
  }
}

function observe(obj) {
  // 希望传入的是obj
  if (typeof obj !== 'object' || obj == null) {
    return;
  }
  // 创建Observer实例
  new Observer(obj);
}

/**
 *  Define a reactive property on an Object.
 */
function defineReactive(obj, key, val) {
  const dep = new Dep();
  // 递归
  observe(val);

  // 对传入obj进行访问拦截
  Object.defineProperty(obj, key, {
    get() {
      console.log('get::' + key + ':' + val);
      // 依赖收集在这里
      console.log('||Dep.target:' + Dep.target);
      Dep.target && dep.addDep(Dep.target);
      // console.log('get::dep:' + dep + '||Dep.target:' + Dep.target);
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        console.log('set ' + key + '=' + newVal);
        // 如果传入的newVal依然是obj，需要做响应化处理
        observe(newVal);
        val = newVal;

        // 通知更新
        dep.notify();
      }
    }
  });
}

/**
 * Define a property.
 */
function def(obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  });
}
